package com.gateway.filter;

import com.alibaba.fastjson2.JSON;
import com.gateway.utils.RedisKey;
import com.gateway.utils.AjaxResponse;
import com.gateway.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jackson.JsonComponentModule;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

/**
 * @author : HUANG
 * @create : 2025/6/1 22:55
 * @function :
 */
@Order(-1)
@Component
public class AuthFilter implements GlobalFilter {
    private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);
    private final String HEAD_AUTH = "Authorization";

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JsonComponentModule jsonComponentModule;
    @Qualifier("reactiveRedisTemplate")
    @Autowired
    private ReactiveRedisTemplate reactiveRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        if (path.startsWith("/client-pet")
                || path.startsWith("/employee-pet")
                ||"/sys/login".equals(request.getPath().toString())
                || request.getPath().toString().contains("/sys/logout")
                || request.getPath().toString().contains("/sys/test")
                || path.equals("/sys/swagger-ui/index.html")
                || path.startsWith("/sys/swagger-ui/")
                || path.equals("/sys/swagger-ui.html")
                || path.startsWith("/sys/v2/api-docs")
                || path.startsWith("/sys/v3/api-docs")
                || path.startsWith("/sys/swagger-resources")
                || path.startsWith("/sys/webjars")
                || path.startsWith("/employee")
                || path.startsWith("/product")
                || path.startsWith("/supplier")
        ) {
            log.info(request.getPath().toString() + "白名单通过");
            request = request.mutate().headers(new Consumer<HttpHeaders>() {
                @Override
                public void accept(HttpHeaders httpHeaders) {
                    httpHeaders.add("userInfo", "WHITE_LIST");
                }
            }).build();
            exchange = exchange.mutate().request(request).build();
            return chain.filter(exchange);
        }
        // 获取请求头中的jwt
        String token = getToken(request);
        // 不存在Jwt
        if (StringUtil.isNullOrEmpty(token)) {
            return buildReturnMono("用户未认证", exchange);
        }
        try {
            Claims claims = JwtUtil.parseJWT(token);
            String userName = claims.getSubject();
            ValueOperations valueOperations = redisTemplate.opsForValue();
            String key = RedisKey.LOGIN_KEY + userName;
            if (!redisTemplate.hasKey(key) || redisTemplate.getExpire(key) < 0) {
                return buildReturnMono("用户认证失败", exchange);
            }
            String json = (String) valueOperations.get(key);
            request = request.mutate().headers(new Consumer<HttpHeaders>() {
                @Override
                public void accept(HttpHeaders httpHeaders) {
                    httpHeaders.add("userInfo", json);
                }
            }).build();
            exchange = exchange.mutate().request(request).build();
            return chain.filter(exchange);
        } catch (Exception e) {
            return buildReturnMono("用户认证失败", exchange);
        }
    }

    private Mono<Void> buildReturnMono(String error, ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        String jsonString = JSON.toJSONString(AjaxResponse.error(400, error));
        byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bits);
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(buffer));
    }

    private String getToken(ServerHttpRequest request) {
        if (request == null) {
            return null;
        }
        return request.getHeaders().getFirst(HEAD_AUTH);
    }
}
